Jump to content
Search Community

GreenSock last won the day on April 21

GreenSock had the most liked content!

GreenSock

Administrators
  • Posts

    23,150
  • Joined

  • Last visited

  • Days Won

    817

GreenSock last won the day on April 21

GreenSock had the most liked content!

About GreenSock

Profile Information

  • Location
    Chicago Area
  • Interests
    Volleyball, Basketball, Christian Apologetics, Motorcycling

Recent Profile Visitors

100,548 profile views

GreenSock's Achievements

  1. That's still considered invalid syntax, though. I suppose it'll default to "-1150px top", for example. I strongly recommend using valid syntax though.
  2. To be clear, I'm not knocking Lenis at all - seems like a great tool. I just wanted to point out that @Publipresse's comparison was missing a few things, like with ScrollSmoother, it smooth ALL forms of scrolling, including dragging the scrollbar, tabbing, using the arrow keys, etc. because it's wired into the NATIVE scrolling position. I'm not very familiar with Lenis, but I think it might be just for wheel scrolling. Both approaches have their up sides and downsides. Neither is "best" - it just depends on what's important to your project. Happy scrolling!
  3. Yeah, that is definitely incorrect. Here's a fork that logs things as they fire: https://codepen.io/GreenSock/pen/JjVVzeM?editors=0010 It's firing: -1, 1, 2, 3, 0, 4, 1, 2 It should go in DESCENDING order because the things at the top of the page should get refreshed first, followed by things further down the page (so the priority should be highest at the top of the page). So the technique you're using there is kinda both inverted and overlapping.
  4. I don't understand why you're doing this: ScrollTrigger.defaults({ smoothScrolling: false }); That doesn't do anything. That's not a valid setting. start: '-1150', end: '-200', Those are not valid values. What are you trying to do? start/end strings are supposed to contain two values, like start: "top bottom" or "-1150 0%". If you want to use specific scroll values (absolute), you can use numbers like start: 1150 (but a negative number doesn't make any sense since you can't scroll backwards past the top of the page). Maybe once we understand what you're trying to do, we can try to provide advice. But the problem here seems to be that you're using faulty/invalid start/end values.
  5. Oh, that's not an actual thing you can install - that was purely a custom interface built for that particular demo that's aimed at helping folks understand the mechanics of timelines. There's GSDevTools for showing a basic scrubber and playback controls: https://gsap.com/docs/v3/Plugins/GSDevTools (it's a Club GSAP membership benefit). Enjoy your learning adventure! 💚
  6. I don't have much time to dig deeply, but this seems problematic to me: tl.to(".rounded-wrapper",{ height:0, // <-- you're altering the layout! }) You've got a ScrollTriggered animation that's suddenly shifting the height of an element above that spot which alters the layout. I wonder why you're doing that. Once I removed that, it seemed to pin without the jump...right? So basically it seems like a logic issue in the way you're altering things. It's collapsing the layout.
  7. You weren't doing proper cleanup. That's a React thing. It calls the useEffect() multiple times in strict mode, and you weren't reverting the tweens/ScrollTriggers properly. So you had duplicates conflicting. That's why it's a good idea to use the useGSAP() hook instead of useEffect() - it handles that for you. You also had a different structure to your markup than in your plain HTML version. I'm not sure exactly what you're trying to do, but maybe this will get you going in the right direction: https://stackblitz.com/edit/react-ztc5vg?file=src%2FApp.js
  8. It looks like your math calculations were off - you were calculating the offset from the current position but you were tweening to absolute numbers rather than relative ones. Is this what you meant to do?: https://codepen.io/GreenSock/pen/XWQQWJK But the problem with that is it's not really responsive. You're animating to specific x/y values but the original top/left absolute positioning is different, so resizing your window will result in different offsets. I think it'd be much cleaner to use a Flip animation instead: https://codepen.io/GreenSock/pen/rNbbNVe?editors=0010 Does that help?
  9. Got a demo illustrating that? I wonder if you're not setting refreshPriority properly. Perhaps you've got it inverted or you've got overlapping values. 🤷‍♂️ 🥳
  10. Yep, same issue - you're creating things out of order, thus they refresh in the wrong order. For example, let's say elementA is 100px from the top of the screen, and there's a ScrollTrigger that triggers when that hits the top of the screen ("top top"). So normally, the start would be 100. But what if there's another ScrollTrigger that pins an element above that one for 1000px - that'd push everything down, thus that element should trigger at 1100px instead of 100px. If ScrollTrigger calculates them in the wrong order, it'd set the first one to a start of 100px (because the pinning one hasn't been factored in yet). Here's a helper function that you can call after all of your elements are in place, and it'll order things based on their proximity to the top of the viewport: function verticalSort() { let scroll = window.pageYOffset; ScrollTrigger.getAll().forEach(t => t._sortY = t.trigger ? scroll + t.trigger.getBoundingClientRect().top : t.start + window.innerHeight); ScrollTrigger.sort((a, b) => a._sortY - b._sortY); } https://codepen.io/GreenSock/pen/ZEZPqyd?editors=0010 Better? Of course you could solve everything by explicitly stating the unique refreshPriority for each, but the above function seemed easier and it should work in most cases.
  11. Yes, like @Rodrigo said, you're creating your ScrollTriggers out-of-order. You're supposed to create them in the order they would be encountered (top to bottom). You're creating the top and bottom first, then the middle, so the refreshing order goes: 1, 3, 2 instead of 1, 2, 3. For relatively simple setups, it could be adequate to just call ScrollTrigger.sort() which will order them by whatever their "start" is calculated to be. But you can explicitly control the order of things by setting a refreshPriority on each one so you have total control of the order. https://codepen.io/GreenSock/pen/PogLyGO?editors=1010 And here's a verticalSort() helper function that'll sort them by their proximity to the very top of the viewport: https://codepen.io/GreenSock/pen/ExJMdXj?editors=0010
  12. In some cases, it's adequate to just call ScrollTrigger.sort() after all the ScrollTriggers are created which will set the refresh order according to the "start" value: https://codepen.io/GreenSock/pen/YzMgQrR?editors=1010 Is that what you're looking for?
  13. Yeah, I don't understand what you're trying to do there, @m__shum. Reverting happens immediately, there's no need to wait for a tick. But you mentioned reverse() (which isn't in your demo) - are you trying to have an animation play in reverse and then after it's done (playhead reaches the start), you want to revert() it? If so, just use onReverseComplete to fire off a function that reverts. It'd be super useful if you provided a minimal demo showing exactly what the problem is. Maybe I'm missing something obvious in your original demo there.
  14. Yeah, that definitely seems like a Firefox rendering bug, totally unrelated to GSAP. My guess is that the renderer needs time to create the raster image for each SVG image. It likely ignores them completely (skips creating the raster) initially because they are display: none. But once it flips to display: block once, that raster image gets created and cached by Firefox, thus it can show it faster next time. Maybe try setting ALL of the images to display: block initially, just for 1 tick maybe so that the browser gets them all rasterized/cached. Rodrigo's suggestion to go with canvas is very good too.
  15. Unfortunately it's just not feasible to make ScrollToPlugin accommodate that automatically. There's no way it could understand which elements are affected by which ScrollTriggers. It's essential that you, as the builder of the page, provide that information. But here's a helper function you could try - it lets you create several lookups that get added together into one big lookup. Splitting them up like this allows you to segregate elements according to whether or not they're in a containerAnimation and/or pinnedContainer: function getScrollLookup(targets, {start, pinnedContainer, containerAnimation}) { targets = gsap.utils.toArray(targets); let initted, triggers = targets.map((el, i) => ScrollTrigger.create({ trigger: el, start: start || "top top", pinnedContainer: pinnedContainer, refreshPriority: -10, onRefresh(self) { if (initted && Math.abs(self.start) > 999999) { triggers[i].kill(); triggers[i] = ScrollTrigger.create({ trigger: el, start: start || "start start", pinnedContainer: pinnedContainer, refreshPriority: -10, }); } }, containerAnimation: containerAnimation })), st = containerAnimation && containerAnimation.scrollTrigger, lookups = [], lookup = target => { let t = gsap.utils.toArray(target)[0], i = targets.indexOf(t); if (i < 0) { for (i = 0; i < lookups.length; i++) { if (lookups[i].targets.indexOf(t) !== -1) { return lookups[i](t); } } return console.warn("target not found", target); } return triggers[i].vars.containerAnimation ? st.start + (triggers[i].start / containerAnimation.duration()) * (st.end - st.start) : triggers[i].start; }; lookup.targets = targets; lookup.add = (targets, config) => { lookups.push(getScrollLookup(targets, config)); return lookup; }; initted = true; return lookup; } So you'd use it like: let lookup = getScrollLookup("section.project", { containerAnimation: tween, pinnedContainer: el }); lookup.add("section.other", {}); // no containerAnimation or pinnedContainer lookup.add("section.pinned", {pinnedContainer: el}); // just a pinned container // then later... let position = lookup(".any-of-the-above-elements"); Hopefully that helps.
×
×
  • Create New...